﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//放置RequirComponent()方法的环境
[RequireComponent(typeof(CharacterController))]
public class RelativeMovement : MonoBehaviour
{

    [SerializeField] private Transform target;
    public float rotSpeed = 15.0f;
    public float moveSpeed = 6.0f;

    private float _vertSpeed;
    public float jumpSpeed = 15.0f;
    public float gravity = -9.8f;
    public float terminalVelocity = -10.0f;
    public float minFall = -1.5f;

    private CharacterController _charController;
    //存储碰撞数据
    private ControllerColliderHit _contact;

    private Animator _animator;
    //要应用的力量值
    public float pushForcs = 3.0f;

	// Use this for initialization
	void Start ()
	{
	    _animator = GetComponent<Animator>();
	    _charController = GetComponent<CharacterController>();
	    _vertSpeed = minFall;
	}
	
	// Update is called once per frame
	void Update () {
		Vector3 movement = Vector3.zero;

	    float horInput = Input.GetAxis("Horizontal");
	    float vertInput = Input.GetAxis("Vertical");
        //按下方向键时只处理移动
	    if (horInput != 0 || vertInput != 0)
	    {
	        movement.x = horInput * moveSpeed;
	        movement.z = vertInput * moveSpeed;
            //限制对角移动速度
            movement = Vector3.ClampMagnitude(movement,moveSpeed);

            //保存初始旋转，以便处理完成目标对象后还原旋转
	        Quaternion tmp = target.rotation;
	        target.eulerAngles = new Vector3(0, target.eulerAngles.y, 0);
            //从Local坐标变为Global坐标
	        movement = target.TransformDirection(movement);
	        target.rotation = tmp;
            //movement朝向
            Quaternion direction = Quaternion.LookRotation(movement);
	        transform.rotation = Quaternion.Lerp(transform.rotation, direction, rotSpeed * Time.deltaTime);
	    }

        _animator.SetFloat("Speed",movement.sqrMagnitude);

	    bool hitGround = false;
	    RaycastHit hit;
        //检查玩家是否在掉落中
	    if (_vertSpeed < 0 && Physics.Raycast(transform.position, Vector3.down, out hit))
	    {
            //检查碰撞的距离，稍微超过胶囊体的底部
	        float check = (_charController.height + _charController.radius) / 1.9f;
	        hitGround = hit.distance <= check;
	    }
        //检查控制器是否在地上
	    if (hitGround)
	    {
            //在地面上时响应Jump键
	        if (Input.GetButtonDown("Jump"))
	        {
	            _vertSpeed = jumpSpeed;
	        }
	        else
	        {
	            _vertSpeed = minFall;
	            _animator.SetBool("Jumping", false);
	        }
	        
	    }
	    else
	    {
	        //如果没在地上则应用重力,直到垂直速到到了终止速度
	        _vertSpeed += gravity * 5 * Time.deltaTime;
	        if (_vertSpeed < terminalVelocity)
	        {
	            _vertSpeed = terminalVelocity;
	        }
            //不在关卡的开始处触发
	        if (_contact != null)
	        {
	            _animator.SetBool("Jumping", true);
	        }
            //光线投射没有检测到地面，但胶囊体接触到了地面
	        if (_charController.isGrounded)
	        {
                //根据角色是否面向接触点,响应稍微不同
	            if (Vector3.Dot(movement, _contact.normal) < 0)
	            {
	                movement = _contact.normal * moveSpeed;
	            }
	            else
	            {
	                movement += _contact.normal * moveSpeed;
	            }
	        }
	    }
        movement.y = _vertSpeed;

        //将movement乘以deltaTime以使它们帧率独立
	    movement *= Time.deltaTime;
	    _charController.Move(movement);
	}

    void OnControllerColliderHit(ControllerColliderHit hit)
    {
        //当检测碰撞时将碰撞数据保存在回调中
        _contact = hit;

        //检查碰撞对象是否有Rigidbody，以便接受物理上的外力
        Rigidbody body = hit.collider.attachedRigidbody;
        if (body != null && !body.isKinematic)
        {
            //将速度应用到物理对象上
            body.velocity = hit.moveDirection * pushForcs;
        }
    }
}
